﻿/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#ifndef SHARED_STORAGE_SQLSTORAGE_H_
#define SHARED_STORAGE_SQLSTORAGE_H_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <cstdint>
#include <map>
#include <boost/unordered_map.hpp>
#include <NodeCpp/Data/Rel/Session.h>
#include "Shared/DBC/DBCLoader.h"
using NodeCpp::Data::Rel::Session;

class SQLStorageBase
{
    template<class DerivedLoader, class StorageClass> friend class SQLStorageLoaderBase;
public:
    /* 获取数据表名称 */
    char const* GetTableName(void) const { return TableName_; }
    /* 获取编号列名称 */
    char const* EntryFieldName(void) const { return EntryField_; }
    /* 获取输出列格式 */
    FieldFormat GetDstFormat(std::uint32_t _Idx) const { return (FieldFormat)DstFormat_[_Idx]; }
    const char* GetDstFormat(void) const { return DstFormat_; }
    /* 获取输入列格式 */
    FieldFormat GetSrcFormat(std::uint32_t _Idx) const { return (FieldFormat)SrcFormat_[_Idx]; }
    const char* GetSrcFormat(void) const { return SrcFormat_; }
    /* 获取数据最大编号 */
    std::uint32_t GetMaxEntry(void) const { return MaxEntry_; }
    /* 获取记录数量 */
    std::uint32_t GetRecordCount(void) const { return RecordCount_; }

    template<typename T>
    class SQLSIterator
    {
        friend class SQLStorageBase;
    public:
        T const* GetValue(void) const { return reinterpret_cast<T const*>(Pointer_); }
        void operator ++(void) { Pointer_ += RecordSize_; }
        T const* operator *(void) const { return GetValue(); }
        T const* operator ->(void) const { return GetValue(); }
        bool operator <(const SQLSIterator& _R) const { return Pointer_ < _R.Pointer_; }
        void operator =(const SQLSIterator& _R) { Pointer_ = _R.Pointer_; RecordSize_ = _R.RecordSize_; }

    private:
        SQLSIterator(char* _Ptr, std::uint32_t _RecordSize) : Pointer_(_Ptr), RecordSize_(_RecordSize) {}

        char* Pointer_;
        std::uint32_t RecordSize_;
    };

    template<typename T>
    SQLSIterator<T> GetDataBegin(void) const { return SQLSIterator<T>(Data_, RecordSize_); }

    template<typename T>
    SQLSIterator<T> GetDataEnd(void) const { return SQLSIterator<T>(Data_ + RecordCount_ * RecordSize_, RecordSize_); }

protected:
    SQLStorageBase(void);
    virtual ~SQLStorageBase(void) { Free(); }

    /* 初始化存储器 */
    // _TableName：数据表名称
    // _EntryField：数据表编号字段名
    // _SrcFormat：输入数据格式
    // _DstFormat：输出数据格式
    void Initialize(const char* _TableName, const char* _EntryField, const char* _SrcFormat, const char* _DstFormat);
    /* 获取输出数据字段数 */
    std::uint32_t GetDstFieldCount(void) const { return DstFieldCount_; }
    /* 获取输入数据字段数 */
    std::uint32_t GetSrcFieldCount(void) const { return SrcFieldCount_; }
    /* 获取记录大小 */
    std::uint32_t GetRecordSize(void) const { return RecordSize_; }

    /* 申请存储空间 */
    virtual void PrepareToLoad(std::uint32_t _MaxRecordId, std::uint32_t _RecordCount, std::uint32_t _RecordSize);
    /*  */
    // _RecordId：记录编号
    // _Record：记录内存地址
    virtual void JustCreatedRecord(std::uint32_t _RecordId, char* _Record) = 0;
    /* 释放数据 */
    virtual void Free(void);

private:
    char* CreateRecord(std::uint32_t _RecordId);

    // Information about the table
    const char* TableName_;
    const char* EntryField_;
    const char* SrcFormat_;
    const char* DstFormat_;

    // Information about the records
    std::uint32_t DstFieldCount_;
    std::uint32_t SrcFieldCount_;
    std::uint32_t RecordCount_;
    std::uint32_t MaxEntry_;
    std::uint32_t RecordSize_;

    // Data Storage
    char* Data_;
};

class SQLStorage : public SQLStorageBase
{
    template<class DerivedLoader, class StorageClass> friend class SQLStorageLoaderBase;

public:
    SQLStorage(const char* _Fmt, const char* _EntryField, const char* _SqlName);
    SQLStorage(const char* _SrcFmt, const char* _DstFmt, const char* _EntryField, const char* _SqlName);
    ~SQLStorage(void) { Free(); }

    template<class T>
    T const* LookupEntry(std::uint32_t _ID) const
    {
        if (_ID >= GetMaxEntry()) {
            return NULL;
        }
        return reinterpret_cast<T const*>(Index_[_ID]);
    }
    void EraseEntry(std::uint32_t _ID);

protected:
    void PrepareToLoad(std::uint32_t _MaxRecordId, std::uint32_t _RecordCount, std::uint32_t _RecordSize) override;
    void JustCreatedRecord(std::uint32_t _RecordId, char* _Record) override
    {
        Index_[_RecordId] = _Record;
    }
    void Free(void) override;

private:
    char** Index_; /**< Lookup access */
};

class SQLHashStorage : public SQLStorageBase
{
    template<class DerivedLoader, class StorageClass> friend class SQLStorageLoaderBase;

public:
    SQLHashStorage(const char* _Fmt, const char* _EntryField, const char* _SqlName);
    SQLHashStorage(const char* _SrcFmt, const char* _DstFmt, const char* _EntryField, const char* _SqlName);
    ~SQLHashStorage(void) { Free(); }

    template<class T>
    T const* LookupEntry(std::uint32_t _ID) const
    {
        RecordMap::const_iterator _Find = IndexMap_.find(_ID);
        if (_Find != IndexMap_.end()) {
            return reinterpret_cast<T const*>(_Find->second);
        }
        return NULL;
    }
    void EraseEntry(std::uint32_t _ID);

protected:
    void PrepareToLoad(std::uint32_t _MaxRecordId, std::uint32_t _RecordCount, std::uint32_t _RecordSize) override;
    void JustCreatedRecord(std::uint32_t _RecordId, char* _Record) override {
        IndexMap_[_RecordId] = _Record;
    }

    void Free() override;

private:
    typedef boost::unordered_map< std::uint32_t /*recordId*/, char* /*record*/ > RecordMap;
    RecordMap IndexMap_;
};

class SQLMultiStorage : public SQLStorageBase
{
    template<class DerivedLoader, class StorageClass> friend class SQLStorageLoaderBase;
    template<typename T> friend class SQLMultiSIterator;
    template<typename T> friend class SQLMSIteratorBounds;

private:
    typedef std::multimap < std::uint32_t /*recordId*/, char* /*record*/ > RecordMultiMap;

public:
    SQLMultiStorage(const char* _Fmt, const char* _EntryField, const char* _SqlName);
    SQLMultiStorage(const char* _SrcFmt, const char* _DstFmt, const char* _EntryField, const char* _SqlName);
    ~SQLMultiStorage(void) { Free(); }

    // forward declaration
    template<typename T> class SQLMSIteratorBounds;

    template<typename T>
    class SQLMultiSIterator
    {
        friend class SQLMultiStorage;
        friend class SQLMSIteratorBounds < T > ;

    public:
        T const* GetValue() const { return reinterpret_cast<T const*>(ConstIterator_->second); }
        std::uint32_t GetKey() const { return ConstIterator_->first; }
        void operator ++() { ++ConstIterator_; }
        T const* operator *() const { return GetValue(); }
        T const* operator ->() const { return GetValue(); }
        bool operator !=(const SQLMultiSIterator& _R) const { return ConstIterator_ != _R.ConstIterator_; }
        bool operator ==(const SQLMultiSIterator& _R) const { return ConstIterator_ == _R.ConstIterator_; }

    private:
        SQLMultiSIterator(RecordMultiMap::const_iterator _Itr) : ConstIterator_(_Itr) {}

        RecordMultiMap::const_iterator ConstIterator_;
    };

    template<typename T>
    class SQLMSIteratorBounds
    {
        friend class SQLMultiStorage;

    public:
        const SQLMultiSIterator<T> first;
        const SQLMultiSIterator<T> second;

    private:
        SQLMSIteratorBounds(std::pair<RecordMultiMap::const_iterator, RecordMultiMap::const_iterator> _Pair) : first(_Pair.first), second(_Pair.second) {}
    };

    template<typename T>
    SQLMSIteratorBounds<T> GetBounds(std::uint32_t _Key) const { return SQLMSIteratorBounds<T>(IndexMultiMap_.equal_range(_Key)); }
    void EraseEntry(std::uint32_t _ID);

protected:
    void PrepareToLoad(std::uint32_t _MaxRecordId, std::uint32_t _RecordCount, std::uint32_t _RecordSize) override;
    void JustCreatedRecord(std::uint32_t _RecordId, char* _Record) override
    {
        IndexMultiMap_.insert(RecordMultiMap::value_type(_RecordId, _Record));
    }
    void Free(void) override;

private:
    RecordMultiMap IndexMultiMap_;
};


///////////////////////////////////////////////////////////////////////////
/* Loader */

template <class DerivedLoader, class StorageClass>
class SQLStorageLoaderBase
{
public:
    template<typename BarType>
    bool Load(Session &_Sess, StorageClass& _Storage, bool _ErrorAtEmpty = true, void(*_ErrorHandler)(const char*, ...) = NULL);

    template<class S, class D>
    void convert(std::uint32_t _FieldPos, S _Src, D& _Dst);
    void convert(std::uint32_t _FieldPos, char _Src, bool& _Dst) { _Dst = (_Src != 0); }
    void convert(std::uint32_t _FieldPos, std::uint32_t _Src, bool& _Dst) { _Dst = (_Src != 0); }
    void convert(std::uint32_t _FieldPos, float _Src, bool& _Dst) {
        _Dst = (_Src > 0.0f || _Src < 0.0f);
    }

    template<class S>
    void convert_to_str(std::uint32_t _FieldPos, S _Src, char*& _Dst);

    template<class D>
    void convert_from_str(std::uint32_t _FieldPos, char const* _Src, D& _Dst);

    void convert_str_to_str(std::uint32_t _FieldPos, char const* _Src, char*& _Dst);

    template<class S, class D>
    void default_fill(std::uint32_t _FieldPos, S _Src, D& _Dst);

    void default_fill_to_str(std::uint32_t _FieldPos, char const* _Src, char*& _Dst);

    template<class D>
    void convert_from_str(std::uint32_t _FieldPos, char* _Src, D& _Dst);

    void convert_str_to_str(std::uint32_t _FieldPos, char* _Src, char*& _Dst);

private:
    template<class V>
    void StoreValue(V _Value, StorageClass& _Store, char* _Record, std::uint32_t _FieldPos, std::uint32_t& _Offset);

    void StoreValue(char const* _Value, StorageClass& _Store, char* _Record, std::uint32_t _FieldPos, std::uint32_t& _Offset);
    void StoreValue(char* _Value, StorageClass& _Store, char* _Record, std::uint32_t _FieldPos, std::uint32_t& _Offset);
};

class SQLStorageLoader : public SQLStorageLoaderBase < SQLStorageLoader, SQLStorage >
{
};


class SQLHashStorageLoader : public SQLStorageLoaderBase < SQLHashStorageLoader, SQLHashStorage >
{
};

class SQLMultiStorageLoader : public SQLStorageLoaderBase < SQLMultiStorageLoader, SQLMultiStorage >
{
};

#endif /* SHARED_STORAGE_SQLSTORAGE_H_ */
